/*树上莫队2
* 1.欧拉序
    欧拉序与dfs序的区别：
    相同点是都会将树中的节点遍历一遍，
    但是dfs序在回溯的时候不会再把存过的节点再存一次，
    而欧拉序是回溯的时候再次把节点存起来，
    所以dfs序的长度为节点个数，欧拉序的长度为节点数的两倍

* 2.做法:
    先将整棵树的欧拉序求出来，
    记录每个点第一次出现的位置 first[i] 和最后一次出现的位置 last[i]，
    然后观察树中的路径 [l,r]（first[l]<first[r]） 可以发现两种情况：
        1.lca(x,y)==x <-> 如果路径是一条从上往下的直链，则其所有点对应欧拉序中 first[l] 到 first[r] 中出现一次的点
        2.lca(x,y)!=x <-> 否则其所有点对应欧拉序中 first[l] 到 last[r] 中出现一次的点加上 lca(l,r)
*/

#define DEBUG
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int N=1e5+10;

inline int read()
{
	int x=0;char c=getchar();
	while (c<'0'||c>'9') c=getchar();
	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48,c=getchar();
	return x;
}
inline void write(int x)
{
	if (x>=10) write(x/10);
	putchar(x%10+48);
}//快读快输

inline int get(int x);

struct Query{
    int l, r, id, type; //type是否包含anc，也记录是第一类询问，还是第二类询问
    bool operator< (const Query& q1) const
    {
        int l1=get(l), l2=get(q1.l);
        return l1!=l2?l1<l2:r<q1.r;
    }
}query[N];

int e[N], ne[N], h[N], idx; //邻接表
int w[N], cnt[N], st[N], res;
int n, m, len;
int f[N][18], depth[N], ans[N], q[N]; //lca
int first[N], last[N], dfn[N], timestamp; //第一次出现的位置 最后一次出现的位置 欧拉序列
vector<int> nums; //离散化

inline void AddEdge(int a, int b)
{
    e[idx]=b, ne[idx]=h[a], h[a]=idx++;
}

inline int get(int x)
{
    return x/len;
}

void dfs(int u, int fa)
{
    dfn[++timestamp]=u; //欧拉序列 进入一次
    first[u]=timestamp;
    for(int i=h[u]; ~i; i=ne[i])
    {
        int v=e[i];
        if(v==fa) continue;
        dfs(v, u);
    }
    dfn[++timestamp]=u; //欧拉序列 回溯一次
    last[u]=timestamp;
}

void bfs()
{
    memset(depth, 0x3f, sizeof depth);
    depth[0]=0, depth[1]=1;
    int hh=0, tt=-1;
    q[++tt]=1;
    while(hh<=tt)
    {
        int u=q[hh++];
        for(int i=h[u]; ~i; i=ne[i])
        {
            int v=e[i];
            if(depth[v]>depth[u]+1)
            {
                depth[v]=depth[u]+1;
                f[v][0]=u;
                for(int k=1; k<17; k++) f[v][k]=f[f[v][k-1]][k-1]; //之前的父亲记录全部向上翻一倍
                q[++tt]=v;
            }
        }
    }

}

int lca(int a, int b) //a>b
{
    if(depth[a]<depth[b]) swap(a, b);
    for(int i=16; i>=0; i--)
        if(depth[f[a][i]] >= depth[b]) a=f[a][i]; //向上回溯到同一层或更高层
    if(a==b) return a;

    for(int i=16; i>=0; i--)
        if(f[a][i] != f[b][i]) a=f[a][i], b=f[b][i]; //回溯到同一父亲
    return f[a][0];
}

void add(int x, int &res)
{
    st[x]^=1;
    if(!st[x])
        res-=!--cnt[w[x]];
    else
        res+=(++cnt[w[x]]==1);
}

signed main()
{
    #ifdef DEBUG
        freopen("./in.txt","r",stdin);
        freopen("./out.txt","w",stdout);
    #endif
    memset(h, -1, sizeof h);

    n=read(); m=read();
    for(int i=1; i<=n; i++) w[i]=read(),  nums.push_back(w[i]);
    sort(nums.begin(), nums.end());

    nums.erase(unique(nums.begin(), nums.end()), nums.end());
    for(int i=1; i<=n; i++) w[i]=lower_bound(nums.begin(), nums.end(), w[i])-nums.begin(); //替换为离散后的值

    for(int i=1; i<n; i++)
    {
        int a=read(), b=read();
        AddEdge(a, b); AddEdge(b, a);
    }

    dfs(1, -1); //求欧拉序列
    bfs();

    for(int i=1; i<=m; i++)
    {
        int a=read(), b=read();
        if(first[a]>first[b]) swap(a, b);
        int anc=lca(a, b);
        if(anc==a) query[i]={first[a], first[b], i}; //再一条直线上
        else query[i]={last[a], first[b], i, anc};
    }
    
    len=sqrt(timestamp);
    sort(query+1, query+1+m);

    for(int i=1, l=1, r=0; i<=m; i++)
    {
        while(query[i].l<l) add(dfn[--l], res);
        while(l<query[i].l) add(dfn[l++], res);
        while(query[i].r<r) add(dfn[r--], res);
        while(r<query[i].r) add(dfn[++r], res);

        if(query[i].type) add(query[i].type, res); //第二类询问需要考虑lca
        ans[query[i].id]=res;
        if(query[i].type) add(query[i].type, res); //恢复
    }

    for(int i=1; i<=m; i++)
        write(ans[i]), puts("");
    return 0;
}